From: tsteven4 Date: Thu, 20 Dec 2018 16:38:22 +0000 (-0700) Subject: add support for multiple urls for route headers. (#276) X-Git-Tag: archive/raspbian/1.10.0+ds-2+rpi1~1^2~12^2~8^2~60 X-Git-Url: https://dgit.raspbian.org/%22http:/www.example.com/cgi/%22https://%22Program/%22http:/www.example.com/cgi/%22https:/%22Program?a=commitdiff_plain;h=49a4123e2643efb0b7abdd444f0a52c05b478519;p=gpsbabel.git add support for multiple urls for route headers. (#276) * add support for multiple urls for route headers. add support in gpx for gpx/rte/link, gpx/rte/url, gpx/rte/urlname. add support in gpx for gpx/trk/link, gpx/trk/url, gpx/trk/urlname. Note that the gpx writer can violate the schema when fprint_xml_chain is used to echo unrecognized elements from input to output. This is because the gpx 1.0/1.1 schema requires an xsd:sequence of elements, i.e. the order of the elements is specified, and any elements output by fprint_xml_chain won't necessarily be in the correct order with other elements that are specifically handled in the gpx writer. By processing additional gpx elements as listed above on read we prevent them from causing schema violations on write. However, other unrecognized elements can still cause schema violations. * make common link code common in gpx reader. --- diff --git a/cst.cc b/cst.cc index 5dd4ba52c..222bef1d0 100644 --- a/cst.cc +++ b/cst.cc @@ -61,7 +61,7 @@ cst_add_wpt(route_head* track, Waypoint* wpt) // Rather than creating a new waypt on each read, tis format bizarrely // recycles the same one, relying on new waypoint(*) above and then manually // resetting fields. Weird. - wpt->url_link_list_.clear(); + wpt->urls.clear(); if (temp_route == nullptr) { temp_route = route_head_alloc(); diff --git a/defs.h b/defs.h index b0df8e743..af26f8054 100644 --- a/defs.h +++ b/defs.h @@ -352,6 +352,24 @@ public: QString url_link_type_; }; +class UrlList : public QList +{ +public: + void AddUrlLink(const UrlLink& l) + { + push_back(l); + } + + bool HasUrlLink() const + { + return !isEmpty(); + } + + const UrlLink& GetUrlLink() const + { + return first(); + } +}; /* * Misc bitfields inside struct waypoint; @@ -484,9 +502,7 @@ public: */ QString notes; - /* TODO: UrlLink should probably move to a "real" class of its own. - */ - QList url_link_list_; + UrlList urls; wp_flags wpt_flags; QString icon_descr; @@ -537,7 +553,7 @@ public: bool HasUrlLink() const; const UrlLink& GetUrlLink() const; - const QList GetUrlLinks() const; + [[deprecated]] const QList GetUrlLinks() const; void AddUrlLink(const UrlLink& l); QString CreationTimeXML() const; gpsbabel::DateTime GetCreationTime() const; @@ -644,7 +660,7 @@ public: queue waypoint_list; /* List of child waypoints */ QString rte_name; QString rte_desc; - QString rte_url; + UrlList rte_urls; int rte_num; int rte_waypt_ct; /* # waypoints in waypoint list */ format_specific_data* fs; diff --git a/garmin_txt.cc b/garmin_txt.cc index 2c7fdb641..8ac16c85f 100644 --- a/garmin_txt.cc +++ b/garmin_txt.cc @@ -629,7 +629,11 @@ route_disp_hdr_cb(const route_head* rte) print_distance(cur_info->length, 0, 1, 0); print_course(cur_info->first_wpt, cur_info->last_wpt); gbfprintf(fout, "\t%d waypoints\t", cur_info->count); - print_string("%s\r\n", rte->rte_url); + if (rte->rte_urls.HasUrlLink()) { + print_string("%s\r\n", rte->rte_urls.GetUrlLink().url_); + } else { + print_string("%s\r\n", ""); + } gbfprintf(fout, "\r\nHeader\t%s\r\n\r\n", headers[rtept_header]); } @@ -681,7 +685,11 @@ track_disp_hdr_cb(const route_head* track) print_date_and_time(cur_info->time, 1); print_distance(cur_info->length, 0, 1, 0); print_speed(&cur_info->length, &cur_info->time); - print_string("%s", track->rte_url); + if (track->rte_urls.HasUrlLink()) { + print_string("%s", track->rte_urls.GetUrlLink().url_); + } else { + print_string("%s", ""); + } gbfprintf(fout, "\r\n\r\nHeader\t%s\r\n\r\n", headers[trkpt_header]); } @@ -1189,7 +1197,7 @@ parse_route_header() rte->rte_name = DUPSTR(str); break; case 5: - rte->rte_url = str; + rte->rte_urls.AddUrlLink(UrlLink(str)); break; } } @@ -1212,7 +1220,7 @@ parse_track_header() trk->rte_name = DUPSTR(str); break; case 6: - trk->rte_url = str; + trk->rte_urls.AddUrlLink(UrlLink(str)); break; } } diff --git a/gdb.cc b/gdb.cc index 3268b0337..41de965fc 100644 --- a/gdb.cc +++ b/gdb.cc @@ -901,9 +901,9 @@ read_route() /* VERSION DEPENDENT CODE */ if (gdb_ver <= GDB_VER_2) { - rte->rte_url = fread_cstr(); + rte->rte_urls.AddUrlLink(UrlLink(fread_cstr())); } else { - rte->rte_url = gdb_fread_strlist(); + rte->rte_urls.AddUrlLink(UrlLink(gdb_fread_strlist())); int color_idx = FREAD_i32; rte->line_color.bbggrr = gt_color_value(color_idx); @@ -971,9 +971,9 @@ read_track() /* VERSION DEPENDENT CODE */ if (gdb_ver >= GDB_VER_3) { - res->rte_url = gdb_fread_strlist(); + res->rte_urls.AddUrlLink(UrlLink(gdb_fread_strlist())); } else { /* if (gdb_ver <= GDB_VER_2) */ - res->rte_url = FREAD_CSTR_AS_QSTR; + res->rte_urls.AddUrlLink(UrlLink(FREAD_CSTR_AS_QSTR)); } #if GDB_DEBUG DBG(GDB_DBG_TRK, !res->rte_url.isNull()) @@ -1327,7 +1327,6 @@ write_waypoint( } FWRITE_CSTR(descr); } else { /* if (gdb_ver > GDB_VER_3) */ - int cnt; // url_link* url_next; // const char* str; QString str; @@ -1362,10 +1361,8 @@ write_waypoint( FWRITE_CSTR(str); /* instruction */ #endif - cnt = 0; - cnt += wpt->url_link_list_.size(); - FWRITE_i32(cnt); - foreach(UrlLink l, wpt->GetUrlLinks()) { + FWRITE_i32(wpt->urls.size()); + foreach(UrlLink l, wpt->urls) { FWRITE_CSTR(l.url_); } } @@ -1518,9 +1515,17 @@ write_route(const route_head* rte, const QString& rte_name) /* VERSION DEPENDENT CODE */ if (gdb_ver <= GDB_VER_2) { - FWRITE_CSTR(rte->rte_url); + if (rte->rte_urls.HasUrlLink()) { + FWRITE_CSTR(rte->rte_urls.GetUrlLink().url_); + } else { + FWRITE_CSTR(""); + } } else { /* if (gdb_ver >= GDB_VER_3) */ - FWRITE_CSTR_LIST(rte->rte_url); + if (rte->rte_urls.HasUrlLink()) { + FWRITE_CSTR_LIST(rte->rte_urls.GetUrlLink().url_); + } else { + FWRITE_CSTR_LIST(""); + } /* "Magenta" (14) is MapSource default */ FWRITE_i32((rte->line_color.bbggrr < 0) ? 14 : gt_color_index_by_rgb(rte->line_color.bbggrr)); FWRITE_C(0); @@ -1560,9 +1565,17 @@ write_track(const route_head* trk, const QString& trk_name) /* VERSION DEPENDENT CODE */ if (gdb_ver <= GDB_VER_2) { - FWRITE_CSTR(trk->rte_url); + if (trk->rte_urls.HasUrlLink()) { + FWRITE_CSTR(trk->rte_urls.GetUrlLink().url_); + } else { + FWRITE_CSTR(""); + } } else { /* if (gdb_ver >= GDB_VER_3 */ - FWRITE_CSTR_LIST(trk->rte_url); + if (trk->rte_urls.HasUrlLink()) { + FWRITE_CSTR_LIST(trk->rte_urls.GetUrlLink().url_); + } else { + FWRITE_CSTR_LIST(""); + } } } diff --git a/gpx.cc b/gpx.cc index 43606dde0..41d1d3e4c 100644 --- a/gpx.cc +++ b/gpx.cc @@ -64,6 +64,7 @@ static QString current_tag; static Waypoint* wpt_tmp; static UrlLink* link_; +static UrlLink* rh_link_; static bool cache_descr_is_html; static gpsbabel::File* iqfile; static gpsbabel::File* oqfile; @@ -169,6 +170,11 @@ typedef enum { tt_rte_name, tt_rte_desc, tt_rte_cmt, + tt_rte_url, /* Not in GPX 1.1 */ + tt_rte_urlname, /* Not in GPX 1.1 */ + tt_rte_link, /* New in GPX 1.1 */ + tt_rte_link_text, /* New in GPX 1.1 */ + tt_rte_link_type, /* New in GPX 1.1 */ tt_rte_number, tt_garmin_rte_display_color, tt_rte_rtept, @@ -176,6 +182,11 @@ typedef enum { tt_trk_desc, tt_trk_name, tt_trk_trkseg, + tt_trk_url, /* Not in GPX 1.1 */ + tt_trk_urlname, /* Not in GPX 1.1 */ + tt_trk_link, /* New in GPX 1.1 */ + tt_trk_link_text, /* New in GPX 1.1 */ + tt_trk_link_type, /* New in GPX 1.1 */ tt_trk_number, tt_garmin_trk_display_color, tt_trk_trkseg_trkpt, @@ -208,7 +219,7 @@ struct GpxGlobal { QStringList url; QStringList urlname; QStringList keywords; - QList link; + UrlList link; /* time and bounds aren't here; they're recomputed. */ }; static GpxGlobal* gpx_global = nullptr; @@ -371,6 +382,11 @@ static tag_mapping tag_path_map[] = { { tt_rte, 0, "/gpx/rte" }, { tt_rte_name, 0, "/gpx/rte/name" }, { tt_rte_desc, 0, "/gpx/rte/desc" }, + { tt_rte_url, 0, "/gpx/rte/url"}, /* GPX 1.0 */ + { tt_rte_urlname, 0, "/gpx/rte/urlname"}, /* GPX 1.0 */ + { tt_rte_link, 0, "/gpx/rte/link"}, /* GPX 1.1 */ + { tt_rte_link_text, 0, "/gpx/rte/link/text"}, /* GPX 1.1 */ + { tt_rte_link_type, 0, "/gpx/rte/link/type"}, /* GPX 1.1 */ { tt_rte_number, 0, "/gpx/rte/number" }, { tt_garmin_rte_display_color, 1, GARMIN_RTE_EXT "/gpxx:DisplayColor"}, @@ -380,6 +396,11 @@ static tag_mapping tag_path_map[] = { { tt_trk_name, 0, "/gpx/trk/name" }, { tt_trk_desc, 0, "/gpx/trk/desc" }, { tt_trk_trkseg, 0, "/gpx/trk/trkseg" }, + { tt_trk_url, 0, "/gpx/trk/url"}, /* GPX 1.0 */ + { tt_trk_urlname, 0, "/gpx/trk/urlname"}, /* GPX 1.0 */ + { tt_trk_link, 0, "/gpx/trk/link"}, /* GPX 1.1 */ + { tt_trk_link_text, 0, "/gpx/trk/link/text"}, /* GPX 1.1 */ + { tt_trk_link_type, 0, "/gpx/trk/link/type"}, /* GPX 1.1 */ { tt_trk_number, 0, "/gpx/trk/number" }, { tt_garmin_trk_display_color, 1, GARMIN_TRK_EXT "/gpxx:DisplayColor"}, @@ -656,6 +677,7 @@ gpx_start(const QString& el, const QXmlStreamAttributes& attr) case tt_rte: rte_head = route_head_alloc(); route_add_head(rte_head); + rh_link_ = new UrlLink; fs_ptr = &rte_head->fs; break; case tt_rte_rtept: @@ -664,6 +686,7 @@ gpx_start(const QString& el, const QXmlStreamAttributes& attr) case tt_trk: trk_head = route_head_alloc(); track_add_head(trk_head); + rh_link_ = new UrlLink; fs_ptr = &trk_head->fs; break; case tt_trk_trkseg_trkpt: @@ -673,6 +696,12 @@ gpx_start(const QString& el, const QXmlStreamAttributes& attr) next_trkpt_is_new_seg = 0; } break; + case tt_rte_link: + case tt_trk_link: + if (attr.hasAttribute("href")) { + link_url = attr.value("href").toString(); + } + break; case tt_unknown: start_something_else(el, attr); return; @@ -900,11 +929,17 @@ gpx_end(const QString&) gpx_add_to_global(gpx_global->keywords, cdatastr); break; case tt_link: - (gpx_global->link).push_back(UrlLink(link_url, link_text, link_type)); + (gpx_global->link).AddUrlLink(UrlLink(link_url, link_text, link_type)); link_type.clear(); link_text.clear(); link_url.clear(); break; + case tt_link_text: + link_text = cdatastr; + break; + case tt_link_type: + link_type = cdatastr; + break; /* * Waypoint-specific tags. @@ -1010,6 +1045,13 @@ gpx_end(const QString&) rte_head->rte_name = cdatastr; break; case tt_rte: + if (rh_link_) { + if (!rh_link_->url_.isEmpty()) { + rte_head->rte_urls.AddUrlLink(*rh_link_); + } + delete rh_link_; + rh_link_ = nullptr; + } break; case tt_rte_rtept: if (link_) { @@ -1028,6 +1070,12 @@ gpx_end(const QString&) case tt_garmin_rte_display_color: rte_head->line_color.bbggrr = gt_color_value_by_name(cdatastr); break; + case tt_rte_link: + rte_head->rte_urls.AddUrlLink(UrlLink(link_url, link_text, link_type)); + link_type.clear(); + link_text.clear(); + link_url.clear(); + break; case tt_rte_number: rte_head->rte_num = cdatastr.toInt(); break; @@ -1038,6 +1086,13 @@ gpx_end(const QString&) trk_head->rte_name = cdatastr; break; case tt_trk: + if (rh_link_) { + if (!rh_link_->url_.isEmpty()) { + trk_head->rte_urls.AddUrlLink(*rh_link_); + } + delete rh_link_; + rh_link_ = nullptr; + } break; case tt_trk_trkseg: next_trkpt_is_new_seg = 1; @@ -1059,6 +1114,12 @@ gpx_end(const QString&) case tt_garmin_trk_display_color: trk_head->line_color.bbggrr = gt_color_value_by_name(cdatastr); break; + case tt_trk_link: + trk_head->rte_urls.AddUrlLink(UrlLink(link_url, link_text, link_type)); + link_type.clear(); + link_text.clear(); + link_url.clear(); + break; case tt_trk_number: trk_head->rte_num = cdatastr.toInt(); break; @@ -1078,6 +1139,22 @@ gpx_end(const QString&) /* * Items that are actually in multiple categories. */ + case tt_rte_url: + case tt_trk_url: + rh_link_->url_ = cdatastr; + break; + case tt_rte_urlname: + case tt_trk_urlname: + rh_link_->url_link_text_ = cdatastr; + break; + case tt_rte_link_text: + case tt_trk_link_text: + link_text = cdatastr; + break; + case tt_rte_link_type: + case tt_trk_link_type: + link_type = cdatastr; + break; case tt_wpttype_ele: wpt_tmp->altitude = cdatastr.toDouble(); break; @@ -1144,12 +1221,6 @@ gpx_end(const QString&) case tt_wpttype_link_type: link_type = cdatastr; break; - case tt_link_text: - link_text = cdatastr; - break; - case tt_link_type: - link_type = cdatastr; - break; case tt_unknown: end_something_else(); return; @@ -1487,26 +1558,42 @@ void free_gpx_extras(xml_tag* tag) /* * Handle the grossness of GPX 1.0 vs. 1.1 handling of linky links. */ +static void +write_gpx_url(const UrlList& urls) +{ + if (gpx_wversion_num > 10) { + for (const auto& l : urls) { + if (!l.url_.isEmpty()) { + writer->writeStartElement(QStringLiteral("link")); + writer->writeAttribute(QStringLiteral("href"), l.url_); + writer->writeOptionalTextElement(QStringLiteral("text"), l.url_link_text_); + writer->writeOptionalTextElement(QStringLiteral("type"), l.url_link_type_); + writer->writeEndElement(); + } + } + } else { + UrlLink l = urls.GetUrlLink(); + if (!l.url_.isEmpty()) { + writer->writeTextElement(QStringLiteral("url"), QString(urlbase) + l.url_); + writer->writeOptionalTextElement(QStringLiteral("urlname"), l.url_link_text_); + } + } +} + static void write_gpx_url(const Waypoint* waypointp) { - if (!waypointp->HasUrlLink()) { - return; + if (waypointp->HasUrlLink()) { + write_gpx_url(waypointp->urls); } +} - if (gpx_wversion_num > 10) { - for (const auto& l : waypointp->GetUrlLinks()) { - writer->writeStartElement(QStringLiteral("link")); - writer->writeAttribute(QStringLiteral("href"), l.url_); - writer->writeOptionalTextElement(QStringLiteral("text"), l.url_link_text_); - writer->writeOptionalTextElement(QStringLiteral("type"), l.url_link_type_); - writer->writeEndElement(); - } - return; +static void +write_gpx_url(const route_head* rh) +{ + if (rh->rte_urls.HasUrlLink()) { + write_gpx_url(rh->rte_urls); } - UrlLink l = waypointp->GetUrlLink(); - writer->writeTextElement(QStringLiteral("url"), QString(urlbase) + l.url_); - writer->writeOptionalTextElement(QStringLiteral("urlname"), l.url_link_text_); } /* @@ -1709,6 +1796,7 @@ gpx_track_hdr(const route_head* rte) writer->writeStartElement(QStringLiteral("trk")); writer->writeOptionalTextElement(QStringLiteral("name"), rte->rte_name); writer->writeOptionalTextElement(QStringLiteral("desc"), rte->rte_desc); + write_gpx_url(rte); if (rte->rte_num) { writer->writeTextElement(QStringLiteral("number"), QString::number(rte->rte_num)); @@ -1797,6 +1885,7 @@ gpx_route_hdr(const route_head* rte) writer->writeStartElement(QStringLiteral("rte")); writer->writeOptionalTextElement(QStringLiteral("name"), rte->rte_name); writer->writeOptionalTextElement(QStringLiteral("desc"), rte->rte_desc); + write_gpx_url(rte); if (rte->rte_num) { writer->writeTextElement(QStringLiteral("number"), QString::number(rte->rte_num)); diff --git a/pocketfms_bc.cc b/pocketfms_bc.cc index 442002256..00283b335 100644 --- a/pocketfms_bc.cc +++ b/pocketfms_bc.cc @@ -85,7 +85,7 @@ read_tracks() trk_head->rte_num = 1; trk_head->rte_name = "PocketFMS"; trk_head->rte_desc = "Breadcrumb"; - trk_head->rte_url = "www.pocketfms.com"; + trk_head->rte_urls.AddUrlLink(UrlLink("www.pocketfms.com")); track_add_head(trk_head); while (1 == gbfread(&bc, sizeof(bc), 1, file_in)) { diff --git a/random.cc b/random.cc index 2e8f9622a..dcfe680cb 100644 --- a/random.cc +++ b/random.cc @@ -131,7 +131,7 @@ random_read() } head->rte_desc = rand_qstr(16, nullptr); if RND(3) { - head->rte_url = rand_qstr(8, "http://rteurl.example.com/%s"); + head->rte_urls.AddUrlLink(UrlLink(rand_qstr(8, "http://rteurl.example.com/%s"))); } } else { head = nullptr; diff --git a/reference/pocketfms_bc.gpx b/reference/pocketfms_bc.gpx index f35b3b94a..30637b0ea 100644 --- a/reference/pocketfms_bc.gpx +++ b/reference/pocketfms_bc.gpx @@ -5,6 +5,7 @@ PocketFMS Breadcrumb + www.pocketfms.com 1 diff --git a/route.cc b/route.cc index af61a2d29..3707dfb66 100644 --- a/route.cc +++ b/route.cc @@ -366,7 +366,7 @@ route_copy(int* dst_count, int* dst_wpt_count, queue** dst, queue* src) route_head* rte_new = route_head_alloc(); rte_new->rte_name = rte_old->rte_name; rte_new->rte_desc = rte_old->rte_desc; - rte_new->rte_url = rte_old->rte_url; + rte_new->rte_urls = rte_old->rte_urls; rte_new->fs = fs_chain_copy(rte_old->fs); rte_new->rte_num = rte_old->rte_num; any_route_add_head(rte_new, *dst); diff --git a/waypt.cc b/waypt.cc index 2015b841f..65dfab024 100644 --- a/waypt.cc +++ b/waypt.cc @@ -381,13 +381,13 @@ waypt_restore(signed int count, queue* head_bak) void waypt_add_url(Waypoint* wpt, const QString& link, const QString& url_link_text) { - wpt->url_link_list_.push_back(UrlLink(link, url_link_text)); + wpt->AddUrlLink(UrlLink(link, url_link_text)); } void waypt_add_url(Waypoint* wpt, const QString& link, const QString& url_link_text, const QString& url_link_type) { - wpt->url_link_list_.push_back(UrlLink(link, url_link_text, url_link_type)); + wpt->AddUrlLink(UrlLink(link, url_link_text, url_link_type)); } double @@ -606,7 +606,7 @@ Waypoint::Waypoint(const Waypoint& other) : shortname(other.shortname), description(other.description), notes(other.notes), - url_link_list_(other.url_link_list_), + urls(other.urls), wpt_flags(other.wpt_flags), icon_descr(other.icon_descr), creation_time(other.creation_time), @@ -649,25 +649,25 @@ Waypoint::Waypoint(const Waypoint& other) : bool Waypoint::HasUrlLink() const { - return !url_link_list_.isEmpty(); + return urls.HasUrlLink(); } const UrlLink& Waypoint::GetUrlLink() const { - return url_link_list_[0]; + return urls.GetUrlLink(); } -const QList +[[deprecated]] const QList Waypoint::GetUrlLinks() const { - return url_link_list_; + return urls; } void Waypoint::AddUrlLink(const UrlLink& l) { - url_link_list_.push_back(l); + urls.AddUrlLink(l); } QString